﻿using System;
using System.Windows.Forms;
using System.Data.Objects;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Linq;
using System.Collections;
using UtfprLibrary.Windows.Forms.ComponentModel;
using UtfprLibrary.EntityFramework.ComponentModel;
using UtfprLibrary.Windows.Forms.Exceptions;

namespace UtfprLibrary.Windows.Forms {
    public partial class UtfprFormQueryBase : UtfprFormBase {
        private UtfprDataSource _utfprDataSource;
        private IBindingList _view;

        public UtfprFormQueryBase() {
            InitializeComponent();
        }

        public UtfprFormQueryBase(ObjectContext context) : this() {
            ObjectContext = context;
            _utfprDataSource = new UtfprDataSource();
        }

        #region Properties

        private ObjectContext _objectContext;
        [Browsable(false)]
        public ObjectContext ObjectContext {
            get { return this._objectContext; }
            set { this._objectContext = value; }
        }

        private object _currentEntity;
        [Browsable(false)]
        public object CurrentEntity {
            get { return _currentEntity; }
            set { _currentEntity = value; }
        }

        private object _keyField;
        [Browsable(false)]
        public object KeyField {
            get { return _keyField; }
            set { _keyField = value; }
        }

        private BindingSource _bindingSource;
        [Category("Data")]
        [Description("Binding Source")]
        public BindingSource BindingSource {
            get { return this._bindingSource; }
            set { this._bindingSource = value; }
        }

        private Button _btnOk;
        [Browsable(false)]
        public Button BtnOK {
            get {
                if (!UtfprControlBase.IsInDesignMode) {
                    if (_btnOk == null) {
                        FieldInfo field = null;
                        var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                        var fieldName = UtfprWindowsFormsConsts.UtfprFormQuery_ButtonOk_FieldName;
                        var frmCrud = this.GetType();

                        field = frmCrud.GetField(fieldName, flags);

                        while (field == null) {
                            if (field == null) {
                                //limita a verificação na hierarquia até no máximo Form
                                if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                                    //recebe o tipo base
                                    frmCrud = frmCrud.BaseType;
                                } else {
                                    break;
                                }
                            }

                            field = frmCrud.GetField(fieldName, flags);
                        }

                        try {
                            _btnOk = field.GetValue(this) as Button;
                        } catch (Exception ex) {
                            throw new UtfprWFCoreFormsException("", ex);
                        }
                    }
                }
                return _btnOk;
            }
        }

        private Button _btnCancel;
        [Browsable(false)]
        public Button BtnCancel {
            get {
                if (!UtfprControlBase.IsInDesignMode) {
                    if (_btnCancel == null) {
                        FieldInfo field = null;
                        var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                        var fieldName = UtfprWindowsFormsConsts.UtfprFormQuery_ButtonCancel_FieldName;
                        var frmCrud = this.GetType();

                        field = frmCrud.GetField(fieldName, flags);

                        while (field == null) {
                            if (field == null) {
                                //limita a verificação na hierarquia até no máximo Form
                                if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                                    //recebe o tipo base
                                    frmCrud = frmCrud.BaseType;
                                } else {
                                    break;
                                }
                            }

                            field = frmCrud.GetField(fieldName, flags);
                        }

                        try {
                            _btnCancel = field.GetValue(this) as Button;
                        } catch (Exception ex) {
                            throw new UtfprWFCoreFormsException("", ex);
                        }

                    }
                }
                return _btnCancel;
            }
        }

        private Button _btnSearch;
        [Browsable(false)]
        public Button BtnSearch {
            get {
                if (!UtfprControlBase.IsInDesignMode) {
                    if (_btnSearch == null) {
                        FieldInfo field = null;
                        var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                        var fieldName = UtfprWindowsFormsConsts.UtfprFormQuery_ButtonSearch_FieldName;
                        var frmCrud = this.GetType();

                        field = frmCrud.GetField(fieldName, flags);

                        while (field == null) {
                            if (field == null) {
                                //limita a verificação na hierarquia até no máximo Form
                                if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                                    //recebe o tipo base
                                    frmCrud = frmCrud.BaseType;
                                } else {
                                    break;
                                }
                            }

                            field = frmCrud.GetField(fieldName, flags);
                        }

                        try {
                            _btnSearch = field.GetValue(this) as Button;
                        } catch (Exception ex) {
                            throw new UtfprWFCoreFormsException("", ex);
                        }

                    }
                }
                return _btnSearch;
            }
        }

        private DataGridView _grdData;
        [Browsable(false)]
        public DataGridView GrdData {
            get {
                if (!UtfprControlBase.IsInDesignMode) {
                    if (_grdData == null) {
                        FieldInfo field = null;
                        var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                        var fieldName = UtfprWindowsFormsConsts.UtfprFormQuery_GridData_FieldName;
                        var frmCrud = this.GetType();

                        field = frmCrud.GetField(fieldName, flags);

                        while (field == null) {
                            if (field == null) {
                                //limita a verificação na hierarquia até no máximo Form
                                if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                                    //recebe o tipo base
                                    frmCrud = frmCrud.BaseType;
                                } else {
                                    break;
                                }
                            }

                            field = frmCrud.GetField(fieldName, flags);
                        }

                        try {
                            _grdData = field.GetValue(this) as DataGridView;
                        } catch (Exception ex) {
                            throw new UtfprWFCoreFormsException("", ex);
                        }

                    }
                }
                return _grdData;
            }
        }

        #endregion

        #region EventHandlers
        
        private void UtfprQueryBase_Load(object sender, EventArgs e) {
            if (!UtfprControlBase.IsInDesignMode) {
                //if (ObjectContext == null) {
                //    throw new UtfprQueryException("ObjectContext", new ArgumentNullException());
                //}

                //if (BindingSource == null) {
                //    throw new UtfprQueryException("BindingSource", new ArgumentNullException());
                //}

                try {
                    BtnOK.Click += new EventHandler(BtnOK_Click);
                    BtnCancel.Click += new EventHandler(BtnCancel_Click);
                    BtnSearch.Click += new EventHandler(BtnSearch_Click);
                    GrdData.CellDoubleClick += new DataGridViewCellEventHandler(GrdData_CellDoubleClick);

                    KeyPreview = true;
                    KeyPress += new KeyPressEventHandler(UtfprQueryBase_KeyPress);
                } catch (Exception ex) {
                    throw new UtfprWFCoreFormsException("", ex);
                }
            }
        }

        void UtfprQueryBase_KeyPress(object sender, KeyPressEventArgs e) {
            e.Handled = false;

            //chama a busca por id quando pressiona o enter
            if (e.KeyChar == (char)Keys.Enter) {
                BtnSearch_Click(sender, e);
            } else if (e.KeyChar == (char)Keys.Escape) {
                BtnCancel_Click(sender, e);
            }
        }

        void GrdData_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
            if (GrdData.CurrentRow != null) {
                CurrentEntity = GrdData.CurrentRow.DataBoundItem;
            }

            DialogResult = DialogResult.OK;
            Close();
        }

        void BtnSearch_Click(object sender, EventArgs e) {
            //bindingSource.EndEdit();

            //object currentValue = null;
            //bool allValuesAreEmpty = true;
            //bool hasKeyMember = false;

            ////neste laço observo todas as propriedades do dataSource procurando por uma EntityKey
            //foreach (PropertyDescriptor pro in bindingSource.CurrencyManager.GetItemProperties()) {
            //    //recuperando o valor da propriedade(EntityKey)
            //    currentValue = pro.GetValue(base.BindingSource.Current);

            //    //verificando se a propriedade atual é uma EntityKey
            //    hasKeyMember = UtfprReflectionHelper.InvokeIsKeyMemberExtentionMethod(
            //        base.Context, base.BindingSource.DataSource, pro.Name);

            //    //se for uma EntityKey e o valor não for nulo
            //    if (hasKeyMember && currentValue != null) {
            //        //se for numérico e maior do que zero
            //        //if (UtfprValueHelper.IsNumeric(currentValue) && UtfprValueHelper.IsGreaterThanZero(currentValue)) {
            //        //então eu sei que devo fazer uma consulta por Id
            //        //=============================
            //        ////////                            GetById((long)currentValue);//fazer uma verificação nesse parse long
            //        //=============================
            //        //caio fora do laço pois já encontrei uma EntityKey válida(ou seja, com um valor)
            //        break;
            //        //}
            //        //se não for uma EntityKey
            //    } else if (currentValue != null) {
            //        //se for uma coleção
            //        if (currentValue is ICollection) {
            //            //se a coleção estiver vazia
            //            if (((ICollection)currentValue).Count == 0) {
            //                //caio fora do laço, pois é como se fosse uma valor nulo
            //                break;
            //            }
            //        }
            //        allValuesAreEmpty = false;
            //        //caio fora do laço pois já encontrei uma propriedade válida(ou seja, com um valor)
            //        break;
            //    }
            //}

            //////se não encontrou nenhuma EntityKey válida
            //if (!hasKeyMember) {
            //    //se todos os parâmetros estiverem vazios
            //    if (allValuesAreEmpty) {
            //        GetAll();
            //    } else {
            //        //GetBy(currentValue)
            //    }
            //}

            ////if (grdData.Rows.Count != 0) {
            ////    _actions = _actions.Search(this);
            ////} else {
            ////    MessageBox.Show("A consulta não retornou nenhum item.", "Informação", MessageBoxButtons.OK, MessageBoxIcon.Information);
            ////}

            new UtfprFormProgressBase("Aguarde...", "Consultando...", true, searchLongOperation).ShowDialog();
            BindingSource.DataSource = _view;
        }

        private void searchLongOperation(object sender, DoWorkEventArgs args) {
            _view = _utfprDataSource.CreateView(Data);
        }

        void BtnCancel_Click(object sender, EventArgs e) {
            //base.BindingSource.Clear();
            DialogResult = DialogResult.Cancel;
            Close();
        }

        void BtnOK_Click(object sender, EventArgs e) {
            if (GrdData.CurrentRow != null) {
                CurrentEntity = GrdData.CurrentRow.DataBoundItem;
            }

            DialogResult = DialogResult.OK;
            Close();
        }

        #endregion

        #region IUtfprQuery

        public object GetCurrentEntity() {
            return CurrentEntity;
        }

        public object GetKeyField() {
            return KeyField;
        }

        public new DialogResult ShowDialog() {
            return base.ShowDialog();
        }

        [Browsable(false)]
        public virtual IEnumerable Data {
            get { throw new NotImplementedException(); }
        }

        #endregion
    }
}